package com.linkdood.app.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.linkdood.app.domain.Organization;
import com.linkdood.app.domain.UserOrganization;
import com.linkdood.app.dto.OrganizationDTO;
import com.linkdood.app.mapper.OrganizationMapper;
import com.linkdood.app.service.OrganizationService;
import com.linkdood.app.service.UserOrganizationService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * dood organization
 *
 * @author YunJ
 */

@Slf4j
@Service
public class OrganizationServiceImpl extends ServiceImpl<OrganizationMapper, Organization> implements OrganizationService {
    public static final String DEFAULT_ORG_NAME = "Organization";
    public static final Long DEFAULT_ORG_ID = -1L;
    public static final String DEFAULT_ORG_CODE = "D1001";

    private final OrganizationMapper organizationMapper;

    private final UserOrganizationService userOrganizationService;

    public OrganizationServiceImpl(OrganizationMapper organizationMapper, UserOrganizationService userOrganizationService) {
        this.organizationMapper = organizationMapper;
        this.userOrganizationService = userOrganizationService;
    }


    @Override
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public Optional<Organization> getOrganization(Long id) {
        log.info("getOrganization() : id={}", id);
        return Optional.of(organizationMapper.selectById(id));
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    @Override
    public Organization getByOrgId(String thirdPartyId, Long orgId) {
        List<Organization> orgs = lambdaQuery().eq(Organization::getThirdPartyId, thirdPartyId).eq(Organization::getOrgId, orgId).list();
        Organization organization;
        if (orgs == null || orgs.isEmpty()) {
            organization = new Organization();
            organization.setThirdPartyId(thirdPartyId);
            organization.setOrgId(orgId);
        } else {
            organization = orgs.get(0);
        }
        return organization;
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    @Override
    public IPage<Organization> pageOrganizationsByOrgId(String thirdPartyId, String orgId, Page<Organization> page) {
        QueryWrapper<Organization> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
            .eq(StringUtils.isNotBlank(orgId), Organization::getOrgId, orgId)
            .eq(StringUtils.isNotBlank(thirdPartyId), Organization::getThirdPartyId, thirdPartyId);
        return organizationMapper.selectPage(page, queryWrapper);
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    @Override
    public long countOrganization() {
        return organizationMapper.selectCount(null);
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    @Override
    public Integer countOrganization(String thirdPartyId) {
        return lambdaQuery().eq(Organization::getThirdPartyId, thirdPartyId).count();
    }

    /**
     * 获取根组织
     */
    @Override
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public List<OrganizationDTO> listRootOrganizations(String thirdPartyId) {
        List<Organization> organization = lambdaQuery()
            .eq(Organization::getThirdPartyId, thirdPartyId)
            .eq(Organization::getParentOrgId, "0")
            .list();
        return organization.stream().map(OrganizationDTO::new).collect(Collectors.toList());
    }

    /**
     * 获取子组织
     */
    @Override
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public List<OrganizationDTO> listSonOrganizations(String thirdPartyId, String orgId) {
        List<Organization> organization = lambdaQuery()
            .eq(Organization::getThirdPartyId, thirdPartyId)
            .eq(Organization::getParentOrgId, orgId)
            .list();
        return organization.stream().map(OrganizationDTO::new).collect(Collectors.toList());
    }

    /**
     * 获取组织架构树
     */
    @Override
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public List<OrganizationDTO> listOrganizationTrees(String thirdPartyId) {
        List<Organization> orgs = lambdaQuery().eq(Organization::getThirdPartyId, thirdPartyId)
                                               .orderByAsc(Organization::getOrgCode).list();
        return buildTree(orgs);
    }

    /**
     *  orgs必须是按照orgCode asc排序好的列表
     */
    private List<OrganizationDTO> buildTree(List<Organization> orgs) {
        List<OrganizationDTO> result = new ArrayList<>();
        if (orgs == null || orgs.size() == 0) {
            OrganizationDTO org1 = new OrganizationDTO();
            org1.setOrgId(DEFAULT_ORG_ID);
            org1.setOrgName(DEFAULT_ORG_NAME);
            org1.setOrgCode(DEFAULT_ORG_CODE);
            org1.setParentOrgId("0");
            result.add(org1);
            return result;
        }

        List<OrganizationDTO> organizationDTOS = transformToOrganizationDTO(orgs);

        for (int i = 0; i < organizationDTOS.size(); i++) {
            OrganizationDTO org =  organizationDTOS.get(i);
            if (org.getOrgCode() == null || StringUtils.equals(org.getParentOrgId(), "0")) {
                result.add(org);
                continue;
            }
            boolean hasParent = false;
            for (int j = i - 1; j >= 0; --j) {
                OrganizationDTO orgPre =  organizationDTOS.get(j);
                if (orgPre.getOrgCode() != null && org.getOrgCode().startsWith(orgPre.getOrgCode())) {
                    if (orgPre.getChildren() == null) {
                        orgPre.setChildren(new ArrayList<>());
                    }
                    orgPre.getChildren().add(org);
                    hasParent = true;
                    break;
                }
            }
            if (!hasParent) {
                result.add(org);
            }
        }
        return result;
    }

    @Override
    public Optional<Organization> getByOrgId(String orgId) {
        return lambdaQuery().eq(Organization::getOrgId, orgId).oneOpt();
    }

    /**
     * 查询用户的所有部门
     *
     * @param userId 用户id
     */
    @Override
    public List<Organization> listByUserId(String userId) {
        List<Organization> result = new ArrayList<>();
        List<UserOrganization> organizationIds = userOrganizationService.listByUserId(userId);
        for (UserOrganization userOrganization : organizationIds) {
            Optional<Organization> organization = getByOrgId(userOrganization.getOrgId());
            organization.ifPresent(result::add);
        }
        return result;
    }

    @Override
    public Optional<Organization> getByOrgIdAndThirdPartyId(String orgId, String thirdPartyId) {
        return lambdaQuery()
                .eq(Organization::getOrgId, orgId)
                .eq(Organization::getThirdPartyId, thirdPartyId)
                .oneOpt();
    }

    @Override
    public List<Organization> listByOrgCodeAndThirdPartyId(String code, String thirdPartyId) {
        return lambdaQuery()
                .likeRight(Organization::getOrgCode, code)
                .eq(Organization::getThirdPartyId, thirdPartyId)
                .list();
    }

    private List<OrganizationDTO> transformToOrganizationDTO(List<Organization> orgs) {
        List<OrganizationDTO> result = new ArrayList<>();
        for (Organization org : orgs) {
            result.add(new OrganizationDTO(org));
        }
        return result;
    }
}
